# uncompyle6 version 3.2.3
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.8 |Anaconda custom (64-bit)| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: helpers\cleanup\on_premise_scan_state.py
__author__ = "Attila Gerendi (Sanyi)"
import uuid, os.path, pathlib, datetime, logging
from dateutil.tz import tzutc
from sqlalchemy import select as sql_select
from settings_provider import settings
from helpers.constants.jobs import ScanAppTypes
from db import Connection
from db.tables.scan_session_jobs import ScanSessionJobRow, ScanSessionJobsTable
from db.tables.scan_sessions import ScanSessionRow, ScanSessionsTable
from db.tables.scans import ScanRow, ScansTable
from db.tables.targets import TargetRow, TargetsTable
from helpers.constants.scans import ScanStatusTypes
from helpers.cleanup.base import Cleanup

_logger = logging.getLogger("helpers.cleanup.on_premise_scan_state")


class CleanupScanState(Cleanup):
    def __init__(self, recurrence, shard_name="master"):
        super().__init__(recurrence)
        select_from = ScanSessionJobsTable.join(
            ScanSessionsTable,
            ScanSessionJobRow.scan_session_id == ScanSessionRow.scan_session_id,
        )
        select_from = select_from.join(
            ScansTable, ScanRow.scan_id == ScanSessionRow.scan_id
        )
        select_from = select_from.join(
            TargetsTable, TargetRow.target_id == ScanSessionRow.target_id
        )
        self._base_query = (
            sql_select((ScanSessionJobRow.status, ScanSessionJobRow.end_date))
            .select_from(select_from)
            .where(ScanSessionRow.deleted_at.is_(None))
            .where(ScanRow.deleted_at.is_(None))
            .where(TargetRow.deleted_at.is_(None))
        )
        self.shard_name = shard_name

    def __check_file(self, file):
        scan_session_id = file.name
        try:
            uuid.UUID(file.name)
        except ValueError:
            return False

        q = self._base_query.where(
            ScanSessionRow.scan_session_id == scan_session_id
        ).where(ScanSessionRow.scan_session_id == scan_session_id)
        with Connection(self.shard_name) as (db):
            result = db.execute(q).fetchone()
            if not result:
                return True
            if result.status in (ScanStatusTypes.FAILED, ScanStatusTypes.ABORTED):
                return True
            if result.status in (ScanStatusTypes.PAUSED, ScanStatusTypes.COMPLETED):
                if result.end_date is None:
                    return True
                x = result.end_date + (
                    datetime.timedelta(
                        hours=settings.get("max_paused_state_hours", 168) + 24
                    )
                )
                if x < datetime.datetime.now(tzutc()):
                    return True
        return False

    def run_once_internal(self):
        scan_state_storage = settings.get("storage.scan_state_db")
        if not scan_state_storage:
            return
        for scan_app in ScanAppTypes.ALL:
            path = pathlib.Path(os.path.join(scan_state_storage, scan_app))
            if not (path.exists() and path.exists()):
                continue
            for file in path.iterdir():
                if self.should_stop:
                    break
                    try:
                        if not file.is_file():
                            continue
                        if self._CleanupScanState__check_file(file):
                            _logger.debug("cleanup obsolete scan state file %s", file)
                            os.remove(str(file))
                    except Exception as e:
                        _logger.exception("failed handling file %s with %s", file, e)
